#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "php.h"
#include "php_openal.h"

/*//. Generic Object Stuff
  ../ Pretty sure this was copy paste from another OOP module. As if I remember
  ../ which one that was. .//*/

//. create new object.
zend_object_value
obj_openal_buffer_new(zend_class_entry *type TSRMLS_DC)
{
	obj_openal_buffer_s *tmp;
	return obj_openal_buffer_mknew(type, &tmp TSRMLS_CC);
}

zend_object_value
obj_openal_buffer_mknew(zend_class_entry *type, obj_openal_buffer_s **obj TSRMLS_DC)
{
	zend_object_value output;
	obj_openal_buffer_s *iobj;
	
	iobj = emalloc(sizeof(obj_openal_buffer_s));
	memset(iobj, 0, sizeof(obj_openal_buffer_s));
	
	iobj->std.ce = type;
	*obj = iobj;
	
	ALLOC_HASHTABLE(iobj->std.properties);
	zend_hash_init(
		iobj->std.properties,
		0,
		NULL,
		ZVAL_PTR_DTOR,
		0
	);
	zend_hash_copy(
		iobj->std.properties,
		&type->default_properties,
		(copy_ctor_func_t)zval_add_ref,
		NULL,
		sizeof(zval *)
	);
	
	output.handle = zend_objects_store_put(
		iobj,
		NULL,
		(zend_objects_free_object_storage_t)obj_openal_buffer_free,
		obj_openal_buffer_clone TSRMLS_CC
	);
	
	output.handlers = &obj_openal_buffer_handlers;
	return output;
}

void
obj_openal_buffer_clone(void *object, void **object_clone TSRMLS_DC)
{
	zend_throw_exception(
		zend_exception_get_default(TSRMLS_C),
		"Unable to clone OpenALBuffer Objects",
		0 TSRMLS_CC
	);
}

void
obj_openal_buffer_free(void *obj TSRMLS_DC)
{
	obj_openal_buffer_s *iobj = (obj_openal_buffer_s *)obj;
	
	zend_hash_destroy(iobj->std.properties);
	FREE_HASHTABLE(iobj->std.properties);
	
	if(alIsBuffer(iobj->buf)) {
		alDeleteBuffers((ALint)1, &iobj->buf);
	}
	
	efree(obj);
}

/*//. Magical Properties
  ../ Supports OpenAL Buffer Read Only Properties, and defaulting back to
  ../ standard operations for non-reserved ones. .//*/

void
obj_openal_buffer_choose_property(const char *property, obj_openal_buffer_prop_s * al) {

	al->prop = AL_NONE;
	al->type = 0;
	al->size = 1;

	if(!strcmp(property,"bits")) { al->prop = AL_BITS; al->type = TYPE_ALINT; al->size = -1; }
	if(!strcmp(property,"channels")) { al->prop = AL_CHANNELS; al->type = TYPE_ALINT; al->size = -1; }
	if(!strcmp(property,"frequency")) { al->prop = AL_FREQUENCY; al->type = TYPE_ALINT; al->size = -1; }
	if(!strcmp(property,"size")) { al->prop = AL_SIZE; al->type = TYPE_ALINT; al->size = -1; }
	return;
}

zval * 
obj_openal_buffer_read_property(zval *object, zval *member, int type TSRMLS_DC)
{
	char *property;
	zval *return_value = NULL;
	obj_openal_buffer_s *this = NULL;
        
	MAKE_STD_ZVAL(return_value);
	this = (obj_openal_buffer_s *)zend_objects_get_address(object TSRMLS_CC);
	property = Z_STRVAL_P(member);

	obj_openal_buffer_prop_s al;
	obj_openal_buffer_choose_property(property, &al);

	if(al.type == TYPE_ALINT) {
		ALint ivalue;
		alGetBufferi(this->buf, al.prop, &ivalue);
		ZVAL_LONG(return_value,(int)ivalue)
	}

	else if(al.prop == AL_NONE) {
		return_value = zend_get_std_object_handlers()->read_property(
			object,
			member,
			type TSRMLS_CC
		);		
	}
	
	if(al.prop != AL_NONE) {
		return_value->refcount = 0;
		return_value->is_ref = 0;
	}
	
	return return_value;
}

void
obj_openal_buffer_write_property(zval *object, zval *member, zval *value TSRMLS_DC)
{
	char err = 0;
	char *property;
	obj_openal_buffer_s *this;
        
	this = (obj_openal_buffer_s *)zend_objects_get_address(object TSRMLS_CC);
	property = Z_STRVAL_P(member);
	
	obj_openal_buffer_prop_s al;
	obj_openal_buffer_choose_property(property, &al);

	if(al.size < 0) {
		php_error(
			E_WARNING,
			"Unable to write to read-only property '%s'",
			property
		);		
	}	
	
	else if(al.prop == AL_NONE) {
		zend_get_std_object_handlers()->write_property(
			object,
			member,
			value TSRMLS_CC
		);
	}
	
	return;
}

/*//. Actual OpenAL Class Methods
  ../ There be sounds here. .//*/

PHP_METHOD(OpenALBuffer, __construct) {
	obj_openal_buffer_s *this = (obj_openal_buffer_s *)zend_object_store_get_object(getThis() TSRMLS_CC);

	//. lol i do stuff here later.

	return;
}

PHP_METHOD(OpenALBuffer, newFromFile)
{
	char *filename;
	int filename_len;

	if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
		return;
	}
	
	ALuint buf;
	
	alGenBuffers(1, &buf);
	if(openal_error_exists()) {
		RETURN_FALSE;
	}
	
	buf = alutCreateBufferFromFile(filename);
	if(buf == 0) {
		RETURN_FALSE;
	}
	
	object_init_ex(return_value, openalbuffer_ce);
	obj_openal_buffer_s *iobj = (obj_openal_buffer_s *)zend_object_store_get_object(return_value TSRMLS_CC);
	iobj->buf = buf;
	
	return;
}

PHP_METHOD(OpenALBuffer, free)
{
	obj_openal_buffer_s *this = (obj_openal_buffer_s *)zend_object_store_get_object(getThis() TSRMLS_CC);

	if(alIsBuffer((ALuint)this->buf)) {
		alDeleteBuffers(1, &this->buf);
	}
}
